package Physics;

public class Vector3 {
	// member variables
	/**
	 * x, y, z coordinates of the vector.
	 */
	public float x, y, z;
	
	/**
	 * Padding to make this class 32 bytes for byte-alignment.
	 * Suppressing warnings about unused for this variable, since
	 * this is intentional.
	 */
	@SuppressWarnings("unused")
	private float padding;
	
	// member functions
	/**
	 * Default constructor: Sets everything to zero.
	 */
	public Vector3() 
	{
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
	}
	
	/**
	 * Implicit constructor
	 */
	public Vector3( float a_x, float a_y, float a_z )
	{
		x = a_x;
		y = a_y;
		z = a_z;
	}
	
	/**
	 * Copy constructor
	 */
	public Vector3( Vector3 other )
	{
		x = other.x;
		y = other.y;
		z = other.z;
	}
	
	/**
	 * Create a vector from the passed OGL object
	 * TODO: Implement OpenGL graphics so we know
	 * what on earth we're supposed to do here...
	 */
	/*Vector3(OGLVector vec)
	{
		x = vec.x;
		y = vec.y;
		z = vec.z;
	}*/
	
	/**
	 * Flips all of the vector components
	 */
	public void invert()
	{
		x *= -1;
		y *= -1;
		z *= -1;
	}
		
	/**
	 * Gets the magnitude (length) of the vector
	 */
	public float magnitude()
	{
		return (float) Math.sqrt(x*x + y*y + z*z);
	}
	
	/**
	 * Gets the magnitude-squared (length-squared)
	 * of the vector.
	 * This is helpful for some calculations so we
	 * don't perform a sqrt() and then square itself.
	 * This would be a waste of processing time.
	 */
	public float squareMagnitude()
	{
		return (x*x + y*y + z*z);
	}
	
	/**
	 * Normalize the vector, keeping its direction
	 * but reducing it to unit-length (length of 1).
	 */
	public void normalize()
	{
		float length = magnitude();
		if (length > 0)
		{
			x /= length;
			y /= length;
			z /= length;
		}
	}
	
	/**
	 * Multiply by a float and set the vector i.e. operator*=()
	 */
	public void multiplyAndSet(float value)
	{
		x *= value;
		y *= value;
		z *= value;
	}
	
	/**
	 * Multiply by a float and return the vector i.e. operator*
	 */
	public Vector3 multiply(float value)
	{
		return (new Vector3(x*value, y*value, z*value));
	}
	
	/**
	 * Add a vector and set it i.e. operator+=
	 */
	public void addAndSet(Vector3 vec)
	{
		x += vec.x;
		y += vec.y;
		z += vec.z;
	}
	
	/**
	 * Add two vectors and return i.e. operator+
	 */
	public Vector3 add(Vector3 vec)
	{
		return (new Vector3(x+vec.x, y+vec.y, z+vec.z));
	}
	
	/**
	 * Subtract a vector and set it i.e. operator-=
	 */
	public void subtractAndSet(Vector3 vec)
	{
		x -= vec.x;
		y -= vec.y;
		z -= vec.z;
	}
	
	/**
	 * Subtract a vector and return it i.e. operator -
	 */
	public Vector3 subtract(Vector3 vec)
	{
		return new Vector3(x-vec.x, y-vec.y, z-vec.z);
	}
	
	/** 
	 * Add a scaled vector. Helpful for incrementing a vector
	 * by another over time e.g. VecA.AddScaledVector(VecB, dt);
	 */
	public void addScaledVector(Vector3 vec, float scaleFactor)
	{
		x += vec.x * scaleFactor;
		y += vec.y * scaleFactor;
		z += vec.z * scaleFactor;
	}
	
	/**
	 * Perform a component product on this vector and the
	 * provided vector,multiplying their components independently.
	 * <br>NOTE: This is neither a dot NOR a cross product!
	 * <br>Use DotProduct() or CrossProduct() for those functions
	 */
	public Vector3 componentProduct(Vector3 vec)
	{
		return new Vector3(x*vec.x, y*vec.y, z*vec.z);
	}
	
	/**
	 * Performs a component product between this vector and
	 * the provided vector, replacing the values in this vector
	 * <br>NOTE: This is neither a dot NOR a cross product!
	 * <br>Use DotProduct() or CrossProduct() for those functions
	 */
	public void componentProductSet(Vector3 vec)
	{
		x *= vec.x;
		y *= vec.y;
		z *= vec.z;
	}
	
	/**
	 * Performs a DOT product between this vector and the
	 * provided vector, returning the value as a float.
	 */
	public float dotProduct(Vector3 vec)
	{
		return (x*vec.x + y*vec.y + z*vec.z);
	}
	
	/**
	 * Performs a CROSS product between this vector and
	 * the provided vector, returning the resultant vector.
	 * <br>The resultant vector will be perpendicular to
	 * the two vectors and of unit length.
	 */
	public Vector3 crossProduct(Vector3 vec)
	{
		return new Vector3(y*vec.z - z*vec.y,
				z*vec.x - x*vec.z,
				x*vec.y - y*vec.x);
	}
	
	/**
	 * Performs a CROSS product between this vector and
	 * the provided vector, REPLACING the values of this vector.
	 * <br>NOTE: In a cross product A x B is not the same
	 * result as B x A. Make sure you use this function on
	 * the right vector.
	 */
	public void crossProductAndSet(Vector3 vec)
	{
		// store the data in a temp variable,
		// since we can't overwrite *this like
		// we could in C++
		Vector3 temp = crossProduct(vec);
		x = temp.x;
		y = temp.y;
		z = temp.z;
	}
	
	/**
	 * Tests if two vectors are equal
	 */
	public boolean equal(Vector3 vec)
	{
		return (x == vec.x && y == vec.y && z == vec.z);
	}
	
	/**
	 * Tests if two vectors are not equal
	 */
	public boolean notEqual(Vector3 vec)
	{
		return !(x == vec.x && y == vec.y && z == vec.z);
	}
	
	/**
	 * Clears the data (sets everything to zero)
	 */
	public void clear()
	{
		x = y = z = 0;
	}
	
	/**
	 * Trims the length of this vector up to the given size
	 */
	public void trim(float size)
	{
		if (squareMagnitude() > size*size)
		{
			normalize();
			x *= size;
			y *= size;
			z *= size;
		}
	}
	
	/**
	 * Sets the individual x, y or z to the value passed in
	 */
	public void setXYZ(int index, float value)
	{
		if(index ==0){
			x = value;
		}
		else if(index == 1){
			y = value;
		}
		else z = value;
	}
	/**
	 * returns the individual x, y or z based on the index passed in
	 */
	public float getXYZ(int index)
	{
		if(index ==0){
			return x;
		}
		else if(index == 1){
			return y;
		}
		else return z;
	}
	/**
	 * Some constant declarations. UP is used often for 
	 * 'camera' up.
	 */
	public static Vector3 UP;
	public static Vector3 DOWN;
	public static Vector3 LEFT;
	public static Vector3 RIGHT;
}
